package testview.zhen.com.myapplication.asm_demo

import org.objectweb.asm.ClassWriter
import org.objectweb.asm.Opcodes
import java.io.FileOutputStream
import java.lang.Exception
import kotlin.Throws
import kotlin.jvm.JvmStatic

/**
 * @author :create by ldr
 * time:2022/10/27 17:18
 * @descript:
 */
class Helloworld : ClassLoader(), Opcodes {
    companion object{
    @Throws(Exception::class)
    @JvmStatic
    fun main(args: Array<String>) {


        //定义一个叫做Example的类
        val cw = ClassWriter(0)
        cw.visit(Opcodes.V1_1, Opcodes.ACC_PUBLIC, "Example", null, "java/lang/Object", null)

        //生成默认的构造方法
        var mw = cw.visitMethod(
            Opcodes.ACC_PUBLIC,
            "<init>",
            "()V",
            null,
            null
        )

        //生成构造方法的字节码指令
        mw.visitVarInsn(Opcodes.ALOAD, 0)
        mw.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V")
        mw.visitInsn(Opcodes.RETURN)
        mw.visitMaxs(1, 1)
        mw.visitEnd()

        //生成main方法
        mw = cw.visitMethod(
            Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC,
            "main",
            "([Ljava/lang/String;)V",
            null,
            null
        )

        //生成main方法中的字节码指令
        mw.visitFieldInsn(
            Opcodes.GETSTATIC,
            "java/lang/System",
            "out",
            "Ljava/io/PrintStream;"
        )
        mw.visitLdcInsn("Hello world111111111!")
        mw.visitMethodInsn(
            Opcodes.INVOKEVIRTUAL,
            "java/io/PrintStream",
            "println",
            "(Ljava/lang/String;)V"
        )
        mw.visitInsn(Opcodes.RETURN)
        mw.visitMaxs(2, 2)

        //字节码生成完成
        mw.visitEnd()

        // 获取生成的class文件对应的二进制流
        val code = cw.toByteArray()


        //将二进制流写到本地磁盘上
        val fos =
            FileOutputStream("./app/src/main/java/testview/zhen/com/myapplication/asm_demo/Example.class")
        fos.write(code)
        fos.close()

        //直接将二进制流加载到内存中
        val loader = Helloworld()
        val exampleClass: Class<*> = loader.defineClass("Example", code, 0, code.size)

        //通过反射调用main方法
        exampleClass.methods[0].invoke(null, *arrayOf(null))
    }
}
}